package com.googlecode.jnarwhal.event;

import java.util.HashMap;
import java.util.HashSet;
import java.util.PriorityQueue;

import com.googlecode.jnarwhal.common.Game;

/**
 * The EventManager is used to: call events,register listeners to be nofified if
 * a certain event is called and manage the event flow
 * 
 * @author Chris
 * 
 */
public class EventManager {

	/**
	 * This HashMap contains the listeners registered to the events. The index
	 * of an event is given by the order defined in Event.Type
	 */
	private static HashMap<Event.Type, HashSet<Listener>> registeredListeners;
	private static PriorityQueue<Event> eventqueue;

	/**
	 * Initialize the EventManager.
	 */
	public static void init() {
		registeredListeners = new HashMap<Event.Type, HashSet<Listener>>();
		for (Event.Type type : Event.Type.values()) {
			registeredListeners.put(type, new HashSet<Listener>());
		}
		eventqueue = new PriorityQueue<Event>();
	}

	/**
	 * Handles all queued events and notifies all registered listeners.
	 * 
	 * @param delta used for time calculations
	 */
	public static void handleEvents(double delta) {
		Event e;
		// while there are still events queued loop
		while ((e = eventqueue.poll()) != null) {
			// notify all the listeners registered to the event type
			for (Listener listener : registeredListeners.get(e.getType())) {
				listener.onEvent(delta, e);
			}
		}
	}

	/**
	 * Call the given event and every registered listener will be notified
	 * 
	 * @param e the event to be called
	 */
	public static void callEvent(Event e) {
		Game.logger.info("event called: " + e.getType().toString());
		eventqueue.add(e);
	}

	/**
	 * Register the given listener to listen for the given event type
	 * 
	 * @param listener
	 * @param type
	 */
	public static void registerListener(Listener listener, Event.Type type) {
		Game.logger.info("registered " + listener.getClass().getName()
				+ " to listen for " + type.toString());
		registeredListeners.get(type).add(listener);
	}

	/**
	 * Unregisters the given listener. The listener will not be notified if the
	 * given event type is called
	 * 
	 * @param listener
	 * @param type
	 */
	public static void unregisterListener(Listener listener, Event.Type type) {
		Game.logger.info("unregistered " + listener.getClass().getName()
				+ " to listen for " + type.toString());
		registeredListeners.get(type).remove(listener);
	}

}
